home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 001 / pibt40s2.arc / PIBASYN1.MOD < prev    next >
Text File  |  1987-09-08  |  56KB  |  935 lines

  1. (*----------------------------------------------------------------------*)
  2. (*         PIBASYNC.PAS   --- Asynchronous I/O for Turbo Pascal         *)
  3. (*----------------------------------------------------------------------*)
  4. (*                                                                      *)
  5. (*  Author:  (c) 1985, 1986, 1987 by Philip R. Burns                    *)
  6. (*                                                                      *)
  7. (*  Version: 1.0   (January, 1985)                                      *)
  8. (*           2.0   (June, 1985)                                         *)
  9. (*           2.1   (July, 1985)                                         *)
  10. (*           3.0   (October, 1985)                                      *)
  11. (*           3.1   (October, 1985)                                      *)
  12. (*           3.2   (November, 1985)                                     *)
  13. (*           4.0   (October, 1986)                                      *)
  14. (*           4.1   (December, 1986)                                     *)
  15. (*           4.2   (January, 1986)                                      *)
  16. (*           4.3   (April, 1987)                                        *)
  17. (*           4.4   (July, 1987)                                         *)
  18. (*                                                                      *)
  19. (*  Systems: For MSDOS/PC DOS on IBM PCs and close compatibles only.    *)
  20. (*                                                                      *)
  21. (*  History: Some of these routines are based upon ones written by:     *)
  22. (*                                                                      *)
  23. (*              Alan Bishop                                             *)
  24. (*              C. J. Dunford                                           *)
  25. (*              Michael Quinlan                                         *)
  26. (*              Gene Harris                                             *)
  27. (*                                                                      *)
  28. (*           I have cleaned up these other authors' code, fixed some    *)
  29. (*           bugs, and added many new features.                         *)
  30. (*                                                                      *)
  31. (*           In particular, starting with v4.0 of PibTerm, both input   *)
  32. (*           and output to the serial port is buffered and interrupt-   *)
  33. (*           driven.  Also, XON/XOFF support has been moved to the      *)
  34. (*           serial port interrupt handler, which results in fewer      *)
  35. (*           overrun problems.                                          *)
  36. (*                                                                      *)
  37. (*           Suggestions for improvements or corrections are welcome.   *)
  38. (*                                                                      *)
  39. (*           If you use this code in your own programs, please be nice  *)
  40. (*           and give proper credit.                                    *)
  41. (*                                                                      *)
  42. (*----------------------------------------------------------------------*)
  43. (*                                                                      *)
  44. (*  Routines:                                                           *)
  45. (*                                                                      *)
  46. (*     BIOS_RS232_Init        ---    Use BIOS to initialize port        *)
  47. (*     DOS_Set_Intrpt         ---    Set interrupt vector using DOS     *)
  48. (*     DOS_Get_Intrpt         ---    Get interrupt vector using DOS     *)
  49. (*     Async_Isr              ---    Com port interrupt service routine *)
  50. (*     Async_Init             ---    Performs initialization.           *)
  51. (*     Async_Clear_Errors     ---    Clear pending serial port errors   *)
  52. (*     Async_Reset_Port       ---    Resets UART parameters for port    *)
  53. (*     Async_Open             ---    Sets up COM port                   *)
  54. (*     Async_Close            ---    Closes down COM port               *)
  55. (*     Async_Carrier_Detect   ---    Checks for modem carrier detect    *)
  56. (*     Async_Carrier_Drop     ---    Checks for modem carrier drop      *)
  57. (*     Async_Buffer_Check     ---    Checks if character in COM buffer  *)
  58. (*     Async_Flush_Output_Buffer --- Flushes output comm buffer         *)
  59. (*     Async_Term_Ready       ---    Toggles terminal ready status      *)
  60. (*     Async_Find_Delay       ---    Find busy wait count for 1ms delay *)
  61. (*     Async_Receive          ---    Reads character from COM buffer    *)
  62. (*     Async_Receive_With_Timeout                                       *)
  63. (*                            ---    Receives char. with timeout check  *)
  64. (*     Async_Ring_Detect      ---    If ringing detected                *)
  65. (*     Async_Send             ---    Transmits char over COM port       *)
  66. (*     Async_Send_String      ---    Sends string over COM port         *)
  67. (*     Async_Send_String_With_Delays                                    *)
  68. (*                            ---    Sends string with timed delays     *)
  69. (*     Async_Send_Break       ---    Sends break (attention) signal     *)
  70. (*     Async_Percentage_Used  ---    Returns percentage com buffer used *)
  71. (*     Async_Purge_Buffer     ---    Purges receive buffer              *)
  72. (*     Async_Release_Buffers  ---    Free memory for serial port queues *)
  73. (*     Async_Setup_Port       ---    Define port base, IRQ, RS232 addr  *)
  74. (*     Async_Stuff            ---    Insert char into receive buffer    *)
  75. (*                                                                      *)
  76. (*----------------------------------------------------------------------*)
  77. (*                                                                      *)
  78. (*      PIBASYNC.PAS was split into PIBASYN1.PAS and PIBASYN2.PAS at    *)
  79. (*      version 3.2 of PibTerm, and into PIBASYN1, PIBASYN2, and        *)
  80. (*      PIBASYN3 for v4.0 of PibTerm.                                   *)
  81. (*                                                                      *)
  82. (*----------------------------------------------------------------------*)
  83.  
  84. (*----------------------------------------------------------------------*)
  85. (*                BIOS_RS232_Init --- Initialize UART                   *)
  86. (*----------------------------------------------------------------------*)
  87.  
  88. PROCEDURE BIOS_RS232_Init( ComPort, ComParm : INTEGER );
  89.  
  90. (*----------------------------------------------------------------------*)
  91. (*                                                                      *)
  92. (*     Procedure:  BIOS_RS232_Init                                      *)
  93. (*                                                                      *)
  94. (*     Purpose:    Issues interrupt $14 to initialize the UART          *)
  95. (*                                                                      *)
  96. (*     Calling Sequence:                                                *)
  97. (*                                                                      *)
  98. (*        BIOS_RS232_Init( ComPort, ComParm : INTEGER );                *)
  99. (*                                                                      *)
  100. (*           ComPort  --- Communications Port Number (0 thru 3)         *)
  101. (*           ComParm  --- Communications Parameter Word                 *)
  102. (*                                                                      *)
  103. (*      Calls:   INTR   (to perform BIOS interrupt $14)                 *)
  104. (*                                                                      *)
  105. (*----------------------------------------------------------------------*)
  106.  
  107. VAR
  108.    Regs: RegPack;
  109.    Save: INTEGER;
  110.  
  111. BEGIN   (* BIOS_RS232_Init *)
  112.                                    (* Set RS 232 base. *)
  113.  
  114.    Save               := MEM[$0:RS232_Base];
  115.    MEM[$0:RS232_Base] := Async_RS232;
  116.  
  117.                                    (* Initialize port    *)
  118.    WITH Regs DO
  119.       BEGIN
  120.          Ax := ComParm AND $00FF;  (* AH=0; AL=ComParm   *)
  121.          Dx := ComPort;            (* Port number to use *)
  122.          INTR($14, Regs);
  123.       END;
  124.                                    (* Set RS 232 base back *)
  125.    MEM[$0:RS232_Base] := Save;
  126.  
  127. END    (* BIOS_RS232_Init *);
  128.  
  129. (*----------------------------------------------------------------------*)
  130. (*             DOS_Set_Intrpt --- Call DOS to set interrupt vector      *)
  131. (*----------------------------------------------------------------------*)
  132.  
  133. PROCEDURE DOS_Set_Intrpt( V, S, O : INTEGER );
  134.  
  135. (*----------------------------------------------------------------------*)
  136. (*                                                                      *)
  137. (*     Procedure:  DOS_Set_Intrpt                                       *)
  138. (*                                                                      *)
  139. (*     Purpose:    Calls DOS to set interrupt vector                    *)
  140. (*                                                                      *)
  141. (*     Calling Sequence:                                                *)
  142. (*                                                                      *)
  143. (*        DOS_Set_Intrpt( V, S, O : INTEGER );                          *)
  144. (*                                                                      *)
  145. (*           V --- interrupt vector number to set                       *)
  146. (*           S --- segment address of interrupt routine                 *)
  147. (*           O --- offset address of interrupt routine                  *)
  148. (*                                                                      *)
  149. (*      Calls:   MSDOS   (to set interrupt)                             *)
  150. (*                                                                      *)
  151. (*----------------------------------------------------------------------*)
  152.  
  153. VAR
  154.    Regs : Regpack;
  155.  
  156. BEGIN   (* DOS_Set_Intrpt *)
  157.  
  158.    WITH Regs DO
  159.       BEGIN
  160.          Ax := $2500 + ( V AND $00FF );
  161.          Ds := S;
  162.          Dx := O;
  163.          Es := 0;
  164.          MsDos( Regs );
  165.       END;
  166.  
  167. END    (* DOS_Set_Intrpt *);
  168.  
  169. (*----------------------------------------------------------------------*)
  170. (*             DOS_Get_Intrpt --- Call DOS to get interrupt vector      *)
  171. (*----------------------------------------------------------------------*)
  172.  
  173. PROCEDURE DOS_Get_Intrpt( V: INTEGER; VAR S: INTEGER; VAR O : INTEGER );
  174.  
  175. (*----------------------------------------------------------------------*)
  176. (*                                                                      *)
  177. (*     Procedure:  DOS_Get_Intrpt                                       *)
  178. (*                                                                      *)
  179. (*     Purpose:    Calls DOS to get interrupt vector                    *)
  180. (*                                                                      *)
  181. (*     Calling Sequence:                                                *)
  182. (*                                                                      *)
  183. (*        DOS_Get_Intrpt( V, S, O : INTEGER );                          *)
  184. (*                                                                      *)
  185. (*           V --- interrupt vector number to get                       *)
  186. (*           S --- segment address of interrupt routine                 *)
  187. (*           O --- offset address of interrupt routine                  *)
  188. (*                                                                      *)
  189. (*      Calls:   MSDOS   (to get interrupt)                             *)
  190. (*                                                                      *)
  191. (*----------------------------------------------------------------------*)
  192.  
  193. VAR
  194.    Regs : Regpack;
  195.  
  196. BEGIN   (* DOS_Get_Intrpt *)
  197.  
  198.    Regs.Ax := $3500 + ( V AND $00FF );
  199.  
  200.    MsDos( Regs );
  201.  
  202.    S := Regs.Es;
  203.    O := Regs.Bx;
  204.  
  205. END    (* DOS_Get_Intrpt *);
  206.  
  207. (*----------------------------------------------------------------------*)
  208. (*               Async_Isr --- Interrupt Service Routine                *)
  209. (*----------------------------------------------------------------------*)
  210.  
  211. PROCEDURE Async_Isr;
  212.  
  213. (*----------------------------------------------------------------------*)
  214. (*                                                                      *)
  215. (*     Procedure:  Async_Isr                                            *)
  216. (*                                                                      *)
  217. (*     Purpose:    Invoked when serial port interrupt occurs.           *)
  218. (*                                                                      *)
  219. (*     Calling Sequence:                                                *)
  220. (*                                                                      *)
  221. (*        Async_Isr;                                                    *)
  222. (*                                                                      *)
  223. (*           --- Called asynchronously only!!!!!!                       *)
  224. (*                                                                      *)
  225. (*----------------------------------------------------------------------*)
  226.  
  227. BEGIN   (* Async_Isr *)
  228.  
  229. INLINE(
  230.   $FB/                                 {         STI                                ;Allow interrupts}
  231.                                        {;}
  232.   $50/                                 {         PUSH    AX                         ;Save registers}
  233.   $53/                                 {         PUSH    BX}
  234.   $51/                                 {         PUSH    CX}
  235.   $52/                                 {         PUSH    DX}
  236.   $1E/                                 {         PUSH    DS}
  237.   $56/                                 {         PUSH    SI}
  238.   $06/                                 {         PUSH    ES}
  239.   $57/                                 {         PUSH    DI}
  240.                                        {;}
  241.                                        {;  Get data segment for addressing global variables}
  242.                                        {;}
  243.   $2E/$8E/$1E/>ASYNC_DSEG_SAVE/        {    CS:  MOV     DS,[>Async_DSeg_Save]}
  244.                                        {;}
  245.                                        {;  Begin major polling loop over pending interrupts.}
  246.                                        {;}
  247.                                        {;  The polling loop is needed because the 8259 cannot handle another 8250}
  248.                                        {;  interrupt while we service this interrupt.  We keep polling here as long}
  249.                                        {;  as an interrupt is received.}
  250.                                        {;}
  251.   $8B/$16/>ASYNC_UART_IIR/             {Poll:    MOV     DX,[>Async_Uart_IIR]       ;Get Interrupt ident register}
  252.   $EC/                                 {         IN      AL,DX                      ;Pick up interrupt type}
  253.                                        {;}
  254.   $A8/$01/                             {         TEST    AL,1                       ;See if any interrupt signalled.}
  255.   $74/$03/                             {         JZ      Polla                      ;Yes --- continue}
  256.   $E9/$7F/$01/                         {         JMP     NEAR Back                  ;No  ---  return to invoker}
  257.                                        {;}
  258.                                        {;  Determine type of interrupt.}
  259.                                        {;  Possibilities:}
  260.                                        {;}
  261.                                        {;     0 = Modem status changed}
  262.                                        {;     2 = Transmit hold register empty (write char)}
  263.                                        {;     4 = Character received from port}
  264.                                        {;     6 = Line status changed}
  265.                                        {;}
  266.   $24/$06/                             {Polla:   AND     AL,6                       ;Strip unwanted bits from interrupt type}
  267.   $3C/$04/                             {         CMP     AL,4                       ;Check if interrupt >= 4}
  268.   $74/$03/                             {         JE      Pollb                      ;}
  269.   $E9/$A1/$00/                         {         JMP     NEAR Int2}
  270.                                        {;}
  271.                                        {;  Write interrupts must be turned on if a higher-priority interrupt}
  272.                                        {;  has been received, else the characters may not be sent (and a lockup}
  273.                                        {;  may occur).}
  274.                                        {;}
  275.   $50/                                 {Pollb:   PUSH    AX                         ;Save interrupt type}
  276.   $E8/$65/$01/                         {         CALL    EnabWI                     ;Enable write interrupts}
  277.   $58/                                 {         POP     AX                         ;Restore interrupt type}
  278.                                        {;}
  279.                                        {;  --- Received a character ----}
  280.                                        {;}
  281.   $3C/$04/                             {Int4:    CMP     AL,4                       ;Check for received char interrupt}
  282.   $74/$03/                             {         JE      Int4a                      ;Yes -- process it.}
  283.   $E9/$95/$00/                         {         JMP     NEAR Int2                  ;No -- skip.}
  284.                                        {;}
  285.                                        {;  Read the character from the serial port.}
  286.                                        {;}
  287.   $8B/$16/>ASYNC_BASE/                 {Int4a:   MOV     DX,[>Async_Base]           ;Read character from port}
  288.   $EC/                                 {         IN      AL,DX}
  289.                                        {;}
  290.                                        {;  Check if XON/XOFF honored.  If so, check if incoming character is}
  291.                                        {;  an XON or an XOFF.}
  292.                                        {;}
  293.   $F6/$06/>ASYNC_DO_XONXOFF/$01/       {         TEST    BYTE [<Async_Do_XonXoff],1 ;See if we honor XON/XOFF}
  294.   $74/$25/                             {         JZ      Int4d                      ;No -- skip XON/XOFF checks}
  295.                                        {;}
  296.   $3C/<XON/                            {         CMP     AL,<XON                    ;See if XON found}
  297.   $74/$11/                             {         JE      Int4b                      ;Skip if XON found}
  298.   $3C/<XOFF/                           {         CMP     AL,<XOFF                   ;See if XOFF found}
  299.   $75/$1D/                             {         JNE     Int4d                      ;Skip if XOFF not found}
  300.                                        {;}
  301.                                        {;  XOFF received -- set flag indicating sending of chars isn't possible}
  302.                                        {;}
  303.   $C6/$06/>ASYNC_XOFF_RECEIVED/$01/    {         MOV     BYTE [<Async_XOFF_Received],1    ;Turn on received XOFF flag}
  304.   $C6/$06/>ASYNC_XOFF_REC_DISPLAY/$01/ {         MOV     BYTE [<Async_XOFF_Rec_Display],1 ;Turn on display flag}
  305.   $E9/$BE/$FF/                         {         JMP     NEAR Poll}
  306.                                        {;}
  307.                                        {;  XON received -- allow more characters to be sent.}
  308.                                        {;}
  309.   $C6/$06/>ASYNC_XOFF_RECEIVED/$00/    {Int4b:   MOV     BYTE [<Async_XOFF_Received],0   ;Turn off received XOFF flag}
  310.   $C6/$06/>ASYNC_XON_REC_DISPLAY/$01/  {         MOV     BYTE [<Async_XON_Rec_Display],1 ;Turn on display flag}
  311.                                        {;}
  312.   $E8/$2F/$01/                         {         CALL    EnabWI                     ;Enable write interrupts}
  313.   $E9/$61/$00/                         {         JMP     NEAR Int4z}
  314.                                        {;}
  315.                                        {;  Not XON/XOFF -- handle other character.}
  316.                                        {;}
  317.   $F6/$06/>ASYNC_LINE_STATUS/$02/      {Int4d:   TEST    BYTE [>Async_Line_Status],2 ;Check for buffer overrun}
  318.   $75/$5A/                             {         JNZ     Int4z                      ;Yes --- don't store anything}
  319.                                        {;}
  320.   $8B/$1E/>ASYNC_BUFFER_HEAD/          {         MOV     BX,[>Async_Buffer_Head]    ;Current position in input buffer}
  321.   $C4/$3E/>ASYNC_BUFFER_PTR/           {         LES     DI,[>Async_Buffer_Ptr]     ;Pick up buffer address}
  322.   $01/$DF/                             {         ADD     DI,BX                      ;Update position}
  323.   $26/$88/$05/                         {     ES: MOV     [DI],AL                    ;Store received character in buffer}
  324.   $FF/$06/>ASYNC_BUFFER_USED/          {         INC     WORD [>Async_Buffer_Used]  ;Increment count of chars in buffer}
  325.                                        {;}
  326.   $A1/>ASYNC_BUFFER_USED/              {         MOV     AX,[>Async_Buffer_Used]    ;Pick up buffer usage count}
  327.   $3B/$06/>ASYNC_MAXBUFFERUSED/        {         CMP     AX,[>Async_MaxBufferUsed]  ;See if greater usage than ever before}
  328.   $7E/$03/                             {         JLE     Int4f                      ;Skip if not}
  329.   $A3/>ASYNC_MAXBUFFERUSED/            {         MOV     [>Async_MaxBufferUsed],AX  ;This is greatest use thus far}
  330.                                        {;}
  331.   $43/                                 {Int4f:   INC     BX                         ;Increment buffer pointer}
  332.   $3B/$1E/>ASYNC_BUFFER_SIZE/          {         CMP     BX,[>Async_Buffer_Size]    ;Check if past end of buffer}
  333.   $7E/$02/                             {         JLE     Int4h}
  334.   $31/$DB/                             {         XOR     BX,BX                      ;If so, wrap around to front}
  335.                                        {;}
  336.   $39/$1E/>ASYNC_BUFFER_TAIL/          {Int4h:   CMP     WORD [>Async_Buffer_Tail],BX ;Check for overflow}
  337.   $74/$29/                             {         JE      Int4s                      ;Jump if head ran into tail}
  338.                                        {;}
  339.   $89/$1E/>ASYNC_BUFFER_HEAD/          {         MOV     [>Async_Buffer_Head],BX    ;Update head pointer}
  340.                                        {;}
  341.                                        {;  If XON/XOFF available, and buffer getting full, set up to send}
  342.                                        {;  XOFF to remote system.}
  343.                                        {;}
  344.                                        {;  This happens in two possible stages:}
  345.                                        {;}
  346.                                        {;     (1)  An XOFF is sent right when the buffer becomes 'Async_Buffer_High'}
  347.                                        {;          characters full.}
  348.                                        {;}
  349.                                        {;     (2)  A second XOFF is sent right when the buffer becomes}
  350.                                        {;          'Async_Buffer_High_2' characters full;  this case is likely the}
  351.                                        {;          result of the remote not having seen our XOFF because it was}
  352.                                        {;          lost in transmission.}
  353.                                        {;}
  354.   $F6/$06/>ASYNC_DO_XONXOFF/$01/       {         TEST    BYTE [<Async_Do_XonXoff],1 ;See if we honor XON/XOFF}
  355.   $74/$23/                             {         JZ      Int4z                      ;No -- skip XON/XOFF checks}
  356.                                        {;}
  357.                                        {;  Check against first high-water mark.}
  358.                                        {;}
  359.   $3B/$06/>ASYNC_BUFFER_HIGH/          {         CMP     AX,[>Async_Buffer_High]    ;AX still has Async_Buffer_Used}
  360.   $7C/$1D/                             {         JL      Int4z                      ;Not very full, so keep going.}
  361.                                        {;}
  362.                                        {;  Check if we've already sent XOFF.}
  363.                                        {;}
  364.   $F6/$06/>ASYNC_XOFF_SENT/$01/        {         TEST    BYTE [<Async_XOFF_Sent],1  ;Remember if we sent XOFF or not}
  365.   $74/$06/                             {         JZ      Int4j                      ;No -- go send it now.}
  366.                                        {;}
  367.                                        {;  Check against second high-water mark.}
  368.                                        {;  If we are right at it, send an XOFF regardless of whether we've}
  369.                                        {;  already sent one or not.  (Perhaps the first got lost.)}
  370.                                        {;}
  371.   $3B/$06/>ASYNC_BUFFER_HIGH_2/        {         CMP     AX,[>Async_Buffer_High_2]}
  372.   $75/$10/                             {         JNE     Int4z                      ;Not at 2nd mark -- skip}
  373.                                        {;}
  374.   $C6/$06/>ASYNC_SEND_XOFF/$01/        {Int4j:   MOV     BYTE [<Async_Send_XOFF],1  ;Indicate we need to send XOFF}
  375.   $E8/$D3/$00/                         {         CALL    EnabWI                     ;Ensure write interrupts enabled}
  376.   $E9/$52/$FF/                         {         JMP     NEAR Poll                  ;}
  377.                                        {;}
  378.                                        {;  If we come here, then the input buffer has overflowed.}
  379.                                        {;  Characters will be thrown away until the buffer empties at least one slot.}
  380.                                        {;}
  381.   $80/$0E/>ASYNC_LINE_STATUS/$02/      {Int4s:   OR      BYTE PTR [>Async_Line_Status],2 ;Flag overrun}
  382.                                        {;}
  383.   $E9/$4A/$FF/                         {Int4z:   JMP     NEAR Poll}
  384.                                        {;}
  385.                                        {;  --- Write a character ---}
  386.                                        {;}
  387.   $3C/$02/                             {Int2:    CMP     AL,2                       ;Check for THRE interrupt}
  388.   $74/$03/                             {         JE      Int2a                      ;Yes -- process it.}
  389.   $E9/$97/$00/                         {         JMP     NEAR Int6                  ;No -- skip.}
  390.                                        {;}
  391.                                        {;  Check first if we need to send an XOFF to remote system.}
  392.                                        {;}
  393.   $F6/$06/>ASYNC_SEND_XOFF/$01/        {Int2a:   TEST    BYTE [<Async_Send_Xoff],1  ;See if we are sending XOFF}
  394.   $74/$34/                             {         JZ      Int2d                      ;No -- skip it}
  395.                                        {;}
  396.                                        {;  Yes, we are to send XOFF to remote.}
  397.                                        {;}
  398.                                        {;  First, check DSR and CTS as requested.}
  399.                                        {;  If those status lines aren't ready, turn off write interrupts and}
  400.                                        {;  try later, after a line status change.}
  401.                                        {;}
  402.   $F6/$06/>ASYNC_DO_DSR/$01/           {         TEST    BYTE [<Async_Do_DSR],1     ;See if DSR checking required}
  403.   $74/$09/                             {         JZ      Int2b                      ;No -- skip it}
  404.                                        {;}
  405.   $8B/$16/>ASYNC_UART_MSR/             {         MOV     DX,[>Async_Uart_MSR]       ;Get modem status register}
  406.   $EC/                                 {         IN      AL,DX}
  407.   $A8/<ASYNC_DSR/                      {         TEST    AL,<Async_DSR              ;Check for Data Set Ready}
  408.   $74/$2E/                             {         JZ      Int2e                      ;If not DSR, turn off write interrupts}
  409.                                        {;}
  410.   $F6/$06/>ASYNC_DO_CTS/$01/           {Int2b:   TEST    BYTE [<Async_Do_CTS],1     ;See if CTS checking required}
  411.   $74/$09/                             {         JZ      Int2c                      ;No -- skip it}
  412.                                        {;}
  413.   $8B/$16/>ASYNC_UART_MSR/             {         MOV     DX,[>Async_Uart_MSR]       ;Get modem status register}
  414.   $EC/                                 {         IN      AL,DX}
  415.   $A8/<ASYNC_CTS/                      {         TEST    AL,<Async_CTS              ;Check for Clear To Send}
  416.   $74/$1E/                             {         JZ      Int2e                      ;If not CTS, turn off write ints}
  417.                                        {;}
  418.                                        {;  All status lines look OK.}
  419.                                        {;  Send the XOFF.}
  420.                                        {;}
  421.   $B0/<XOFF/                           {Int2c:   MOV     AL,<XOFF                   ;Get XOFF Character}
  422.   $8B/$16/>ASYNC_BASE/                 {         MOV     DX,[>Async_Base]           ;Get transmit hold register address}
  423.   $EE/                                 {         OUT     DX,AL                      ;Output the XOFF}
  424.   $C6/$06/>ASYNC_SEND_XOFF/$00/        {         MOV     BYTE [<Async_Send_XOFF],0  ;Turn off send XOFF flag}
  425.   $C6/$06/>ASYNC_XOFF_SENT/$01/        {         MOV     BYTE [<Async_XOFF_Sent],1  ;Turn on sent XOFF flag}
  426.   $E9/$08/$FF/                         {         JMP     NEAR Poll                  ;Return}
  427.                                        {;}
  428.                                        {;  Not sending XOFF -- see if any character in buffer to be sent.}
  429.                                        {;}
  430.   $8B/$1E/>ASYNC_OBUFFER_TAIL/         {Int2d:   MOV     BX,[>Async_OBuffer_Tail]   ;Pick up output buffer pointers}
  431.   $3B/$1E/>ASYNC_OBUFFER_HEAD/         {         CMP     BX,[>Async_OBuffer_Head]}
  432.   $75/$0B/                             {         JNE     Int2m                      ;Skip if not equal --> something to send}
  433.                                        {;}
  434.                                        {;  If nothing to send, turn off write interrupts to avoid unnecessary}
  435.                                        {;  time spent handling useless THRE interrupts.}
  436.                                        {;}
  437.   $8B/$16/>ASYNC_UART_IER/             {Int2e:   MOV     DX,[>Async_Uart_IER]       ;If nothing -- or can't -- send ...}
  438.   $EC/                                 {         IN      AL,DX                      ;}
  439.   $24/$FD/                             {         AND     AL,$FD                     ;}
  440.   $EE/                                 {         OUT     DX,AL                      ;... disable write interrupts}
  441.   $E9/$F3/$FE/                         {         JMP     NEAR Poll                  ;}
  442.                                        {;}
  443.                                        {;  If something to send, ensure that remote system didn't send us XOFF.}
  444.                                        {;  If it did, we can't send anything, so turn off write interrupts and}
  445.                                        {;  wait for later (after an XON has been received).}
  446.                                        {;}
  447.   $F6/$06/>ASYNC_XOFF_RECEIVED/$01/    {Int2m:   TEST    BYTE [<Async_XOFF_Received],1 ;See if we received XOFF}
  448.   $75/$EE/                             {         JNZ     Int2e                      ;Yes -- can't send anything now}
  449.                                        {;}
  450.                                        {;  If we can send character, check DSR and CTS as requested.}
  451.                                        {;  If those status lines aren't ready, turn off write interrupts and}
  452.                                        {;  try later, after a line status change.}
  453.                                        {;}
  454.   $8B/$16/>ASYNC_UART_MSR/             {         MOV     DX,[>Async_Uart_MSR]       ;Otherwise get modem status}
  455.   $EC/                                 {         IN      AL,DX}
  456.   $A2/>ASYNC_MODEM_STATUS/             {         MOV     [>Async_Modem_Status],AL   ;and save modem status for later}
  457.                                        {;}
  458.   $F6/$06/>ASYNC_DO_DSR/$01/           {         TEST    BYTE [<Async_Do_DSR],1     ;See if DSR checking required}
  459.   $74/$04/                             {         JZ      Int2n                      ;No -- skip it}
  460.                                        {;}
  461.   $A8/<ASYNC_DSR/                      {         TEST    AL,<Async_DSR              ;Check for Data Set Ready}
  462.   $74/$DB/                             {         JZ      Int2e                      ;If not DSR, turn off write ints}
  463.                                        {;}
  464.   $F6/$06/>ASYNC_DO_CTS/$01/           {Int2n:   TEST    BYTE [<Async_Do_CTS],1     ;See if CTS checking required}
  465.   $74/$04/                             {         JZ      Int2o                      ;No -- skip it}
  466.                                        {;}
  467.   $A8/<ASYNC_CTS/                      {         TEST    AL,<Async_CTS              ;Check for Clear To Send}
  468.   $74/$D0/                             {         JZ      Int2e                      ;If not CTS, turn off write ints}
  469.                                        {;}
  470.                                        {;  Everything looks OK for sending, so send the character.}
  471.                                        {;}
  472.   $C4/$3E/>ASYNC_OBUFFER_PTR/          {Int2o:   LES     DI,[>Async_OBuffer_Ptr]    ;Get output buffer pointer}
  473.   $01/$DF/                             {         ADD     DI,BX                      ;Position to character to output}
  474.   $26/$8A/$05/                         {     ES: MOV     AL,[DI]                    ;Get character to output}
  475.   $8B/$16/>ASYNC_BASE/                 {         MOV     DX,[>Async_Base]           ;Get transmit hold register address}
  476.   $EE/                                 {         OUT     DX,AL                      ;Output the character}
  477.                                        {;}
  478.   $FF/$0E/>ASYNC_OBUFFER_USED/         {         DEC     WORD [>Async_OBuffer_Used] ;Decrement count of chars in buffer}
  479.   $43/                                 {         INC     BX                         ;Increment tail pointer}
  480.   $3B/$1E/>ASYNC_OBUFFER_SIZE/         {         CMP     BX,[>Async_OBuffer_Size]   ;See if past end of buffer}
  481.   $7E/$02/                             {         JLE     Int2z}
  482.   $31/$DB/                             {         XOR     BX,BX                      ;If so, wrap to front}
  483.                                        {;}
  484.   $89/$1E/>ASYNC_OBUFFER_TAIL/         {Int2z:   MOV     [>Async_OBuffer_Tail],BX   ;Store updated buffer tail}
  485.   $E9/$AC/$FE/                         {         JMP     NEAR Poll}
  486.                                        {;}
  487.                                        {;  --- Line status change ---}
  488.                                        {;}
  489.   $3C/$06/                             {Int6:    CMP     AL,6                       ;Check for line status interrupt}
  490.   $75/$11/                             {         JNE     Int0                       ;No -- skip.}
  491.                                        {;}
  492.   $8B/$16/>ASYNC_UART_LSR/             {         MOV     DX,[>Async_Uart_LSR]       ;Yes -- pick up line status register}
  493.   $EC/                                 {         IN      AL,DX                      ;and its contents}
  494.   $24/$1E/                             {         AND     AL,$1E                     ;Strip unwanted bits}
  495.   $A2/>ASYNC_LINE_STATUS/              {         MOV     [>Async_Line_Status],AL    ;Store for future reference}
  496.   $08/$06/>ASYNC_LINE_ERROR_FLAGS/     {         OR      [>Async_Line_Error_Flags],AL ;Add to any past transgressions}
  497.   $E9/$97/$FE/                         {         JMP     NEAR Poll}
  498.                                        {;}
  499.                                        {;  --- Modem status change ---}
  500.                                        {;}
  501.   $3C/$00/                             {Int0:    CMP     AL,0                       ;Check for modem status change}
  502.   $74/$03/                             {         JE      Int0a                      ;Yes -- handle it}
  503.   $E9/$90/$FE/                         {         JMP     NEAR Poll                  ;Else get next interrupt}
  504.                                        {;}
  505.   $8B/$16/>ASYNC_UART_MSR/             {Int0a:   MOV     DX,[>Async_Uart_MSR]       ;Pick up modem status reg. address}
  506.   $EC/                                 {         IN      AL,DX                      ;and its contents}
  507.   $A2/>ASYNC_MODEM_STATUS/             {         MOV     [>Async_Modem_Status],AL   ;Store for future reference}
  508.   $E8/$03/$00/                         {         CALL    EnabWI                     ;Turn on write interrupts, in case}
  509.                                        {;                                           ;status change resulted from CTS/DSR}
  510.                                        {;                                           ;changing state.}
  511.   $E9/$82/$FE/                         {         JMP     NEAR Poll}
  512.                                        {;}
  513.                                        {;  Internal subroutine to enable write interrupts.}
  514.                                        {;}
  515.                                        {EnabWI: ;PROC    NEAR}
  516.   $8B/$16/>ASYNC_UART_IER/             {         MOV     DX,[>Async_Uart_IER]       ;Get interrupt enable register}
  517.   $EC/                                 {         IN      AL,DX                      ;Check contents of IER}
  518.   $A8/$02/                             {         TEST    AL,2                       ;See if write interrupt enabled}
  519.   $75/$03/                             {         JNZ     EnabRet                    ;Skip if so}
  520.   $0C/$02/                             {         OR      AL,2                       ;Else enable write interrupts ...}
  521.   $EE/                                 {         OUT     DX,AL                      ;... by rewriting IER contents}
  522.   $C3/                                 {EnabRet: RET                                ;Return to caller}
  523.                                        {;}
  524.                                        {;  Send non-specific EOI to 8259 controller.}
  525.                                        {;}
  526.   $B0/$20/                             {Back:    MOV     AL,$20                     ;EOI = $20}
  527.   $E6/$20/                             {         OUT     $20,AL}
  528.                                        {;}
  529.                                        {;  Restore registers}
  530.                                        {;}
  531.   $5F/                                 {         POP     DI}
  532.   $07/                                 {         POP     ES}
  533.   $5E/                                 {         POP     SI}
  534.   $1F/                                 {         POP     DS}
  535.   $5A/                                 {         POP     DX}
  536.   $59/                                 {         POP     CX}
  537.   $5B/                                 {         POP     BX}
  538.   $58/                                 {         POP     AX}
  539.   $89/$EC/                             {         MOV     SP,BP}
  540.   $5D/                                 {         POP     BP}
  541.   $CF);                                {         IRET}
  542.  
  543. END    (* Async_Isr *);
  544.  
  545. (*----------------------------------------------------------------------*)
  546. (*               Async_Close --- Close down communications interrupts   *)
  547. (*----------------------------------------------------------------------*)
  548.  
  549. PROCEDURE Async_Close( Drop_DTR: BOOLEAN );
  550.  
  551. (*----------------------------------------------------------------------*)
  552. (*                                                                      *)
  553. (*     Procedure:  Async_Close                                          *)
  554. (*                                                                      *)
  555. (*     Purpose:    Resets interrupt system when UART interrupts         *)
  556. (*                 are no longer needed.                                *)
  557. (*                                                                      *)
  558. (*     Calling Sequence:                                                *)
  559. (*                                                                      *)
  560. (*        Async_Close( Drop_DTR : BOOLEAN );                            *)
  561. (*                                                                      *)
  562. (*           Drop_DTR --- TRUE to drop DTR when closing down port       *)
  563. (*                                                                      *)
  564. (*     Calls:  None                                                     *)
  565. (*                                                                      *)
  566. (*----------------------------------------------------------------------*)
  567.  
  568. VAR
  569.    I : INTEGER;
  570.    M : INTEGER;
  571.  
  572. BEGIN  (* Async_Close *)
  573.  
  574.    IF Async_Open_Flag THEN
  575.       BEGIN
  576.  
  577.                      (* disable the IRQ on the 8259 *)
  578.  
  579.          INLINE($FA);                 (* disable interrupts *)
  580.  
  581.          I := Port[I8088_IMR];        (* get the interrupt mask register *)
  582.          M := 1 SHL Async_Irq;        (* set mask to turn off interrupt  *)
  583.          Port[I8088_IMR] := I OR M;
  584.  
  585.                      (* disable the 8250 interrupts *)
  586.  
  587.          Port[UART_IER + Async_Base] := 0;
  588.  
  589.                      (* Disable OUT2, RTS, OUT1 on the 8250, but *)
  590.                      (* possibly leave DTR enabled.              *)
  591.  
  592.          IF Drop_Dtr THEN
  593.             Port[UART_MCR + Async_Base] := 0
  594.          ELSE
  595.             Port[UART_MCR + Async_Base] := 1;
  596.  
  597.          INLINE($FB);                 (* enable interrupts *)
  598.  
  599.                      (* re-initialize our data areas so we know *)
  600.                      (* the port is closed                      *)
  601.  
  602.          Async_Open_Flag := FALSE;
  603.          Async_XOFF_Sent := FALSE;
  604.  
  605.                      (* Restore the previous interrupt pointers *)
  606.  
  607.          DOS_Set_Intrpt( Async_Irq + 8 , Async_Save_Iaddr[1],
  608.                                          Async_Save_Iaddr[2]  );
  609.  
  610.       END;
  611.  
  612. END    (* Async_Close *);
  613.  
  614. (*----------------------------------------------------------------------*)
  615. (*    Async_Clear_Errors --- Reset pending errors in async port         *)
  616. (*----------------------------------------------------------------------*)
  617.  
  618. PROCEDURE Async_Clear_Errors;
  619.  
  620. (*----------------------------------------------------------------------*)
  621. (*                                                                      *)
  622. (*     Procedure:   Async_Clear_Errors                                  *)
  623. (*                                                                      *)
  624. (*     Purpose:     Resets pending errors in async port                 *)
  625. (*                                                                      *)
  626. (*     Calling sequence:                                                *)
  627. (*                                                                      *)
  628. (*        Async_Clear_Errors;                                           *)
  629. (*                                                                      *)
  630. (*     Calls:  None                                                     *)
  631. (*                                                                      *)
  632. (*----------------------------------------------------------------------*)
  633.  
  634. VAR
  635.    I:  INTEGER;
  636.    M:  INTEGER;
  637.  
  638. BEGIN (* Async_Clear_Errors *)
  639.  
  640.                    (* Read the RBR and reset any pending error conditions. *)
  641.                    (* First turn off the Divisor Access Latch Bit to allow *)
  642.                    (* access to RBR, etc.                                  *)
  643.  
  644.    INLINE($FA);  (* disable interrupts *)
  645.  
  646.    Port[UART_LCR + Async_Base] := Port[UART_LCR + Async_Base] AND $7F;
  647.  
  648.                    (* Read the Line Status Register to reset any errors *)
  649.                    (* it indicates                                      *)
  650.  
  651.    I := Port[UART_LSR + Async_Base];
  652.  
  653.                    (* Read the Receiver Buffer Register in case it *)
  654.                    (* contains a character                         *)
  655.  
  656.    I := Port[UART_RBR + Async_Base];
  657.  
  658.                    (* enable the irq on the 8259 controller *)
  659.  
  660.    I := Port[I8088_IMR];  (* get the interrupt mask register *)
  661.    M := (1 SHL Async_Irq) XOR $00FF;
  662.  
  663.    Port[I8088_IMR] := I AND M;
  664.  
  665.                    (* enable OUT2 on 8250 *)
  666.  
  667.    I := Port[UART_MCR + Async_Base];
  668.    Port[UART_MCR + Async_Base] := I OR $0B;
  669.  
  670.                    (* enable the data ready interrupt on the 8250 *)
  671.  
  672.    Port[UART_IER + Async_Base] := $0F;
  673.  
  674.                    (* Re-enable 8259 *)
  675.  
  676.    Port[$20] := $20;
  677.  
  678.    INLINE($FB); (* enable interrupts *)
  679.  
  680. END   (* Async_Clear_Errors *);
  681.  
  682. (*----------------------------------------------------------------------*)
  683. (*    Async_Reset_Port --- Set/reset communications port parameters     *)
  684. (*----------------------------------------------------------------------*)
  685.  
  686. PROCEDURE Async_Reset_Port( ComPort       : INTEGER;
  687.                             BaudRate      : INTEGER;
  688.                             Parity        : CHAR;
  689.                             WordSize      : INTEGER;
  690.                             StopBits      : INTEGER  );
  691.  
  692. (*----------------------------------------------------------------------*)
  693. (*                                                                      *)
  694. (*     Procedure:   Async_Reset_Port                                    *)
  695. (*                                                                      *)
  696. (*     Purpose:     Resets communications port                          *)
  697. (*                                                                      *)
  698. (*     Calling Sequence:                                                *)
  699. (*                                                                      *)
  700. (*        Async_Reset_Port(   ComPort       : INTEGER;                  *)
  701. (*                            BaudRate      : INTEGER;                  *)
  702. (*                            Parity        : CHAR;                     *)
  703. (*                            WordSize      : INTEGER;                  *)
  704. (*                            StopBits      : INTEGER);                 *)
  705. (*                                                                      *)
  706. (*           ComPort  --- which port (1, 2, 3)                          *)
  707. (*           BaudRate --- Baud rate (110 to 19200)                      *)
  708. (*           Parity   --- "E" for even, "O" for odd, "N" for none,      *)
  709. (*                        "M" for mark, "S" for space.
  710. (*           WordSize --- Bits per character  (5 through 8)             *)
  711. (*           StopBits --- How many stop bits  (1 or 2)                  *)
  712. (*                                                                      *)
  713. (*     Calls:                                                           *)
  714. (*                                                                      *)
  715. (*        Async_Clear_Errors --- Clear async line errors                *)
  716. (*                                                                      *)
  717. (*----------------------------------------------------------------------*)
  718.  
  719. CONST   (* Baud Rate Constants *)
  720.  
  721.    Async_Num_Bauds = 9;
  722.  
  723.    Async_Baud_Table : ARRAY [1..Async_Num_Bauds] OF RECORD
  724.                                                        Baud, Bits : INTEGER;
  725.                                                     END
  726.  
  727.                     = ( ( Baud:  110;  Bits: $00 ),
  728.                         ( Baud:  150;  Bits: $20 ),
  729.                         ( Baud:  300;  Bits: $40 ),
  730.                         ( Baud:  600;  Bits: $60 ),
  731.                         ( Baud:  1200; Bits: $80 ),
  732.                         ( Baud:  2400; Bits: $A0 ),
  733.                         ( Baud:  4800; Bits: $C0 ),
  734.                         ( Baud:  9600; Bits: $E0 ),
  735.                         ( Baud: 19200; Bits: $E0 ) );
  736.  
  737. VAR
  738.    I       : INTEGER;
  739.    ComParm : INTEGER;
  740.  
  741. BEGIN (* Async_Reset_Port *)
  742.  
  743.             (*---------------------------------------------------*)
  744.             (*    Build the ComParm for RS232_Init               *)
  745.             (*    See Technical Reference Manual for description *)
  746.             (*---------------------------------------------------*)
  747.  
  748.                                    (* Set up the bits for the baud rate *)
  749.  
  750.    IF ( BaudRate > Async_Baud_Table[Async_Num_Bauds].Baud ) THEN
  751.       BaudRate := Async_Baud_Table[Async_Num_Bauds].Baud
  752.  
  753.    ELSE IF ( BaudRate < Async_Baud_Table[1].Baud ) THEN
  754.       BaudRate := Async_Baud_Table[1].Baud;
  755.  
  756.                                    (* Remember baud rate for purges *)
  757.    Async_Baud_Rate := BaudRate;
  758.  
  759.    I := 0;
  760.  
  761.    REPEAT
  762.       I := I + 1
  763.    UNTIL ( ( I >= Async_Num_Bauds ) OR
  764.            ( BaudRate = Async_Baud_Table[I].Baud ) );
  765.  
  766.    ComParm := Async_Baud_Table[I].Bits;
  767.  
  768.                                    (* Choose Parity.  Temporarily   *)
  769.                                    (* consider mark, space as none. *)
  770.    Parity := UpCase( Parity );
  771.  
  772.    CASE Parity OF
  773.       'E' : ComParm := ComParm OR $0018;
  774.       'O' : ComParm := ComParm OR $0008;
  775.       ELSE ;
  776.    END (* CASE *);
  777.                                    (* Choose number of data bits *)
  778.  
  779.    WordSize := WordSize - 5;
  780.  
  781.    IF ( WordSize < 0 ) OR ( WordSize > 3 ) THEN
  782.       WordSize := 3;
  783.  
  784.    ComParm := ComParm OR WordSize;
  785.  
  786.                                    (* Choose stop bits *)
  787.  
  788.    IF StopBits = 2 THEN
  789.       ComParm := ComParm OR $0004;  (* default is 1 stop bit *)
  790.  
  791.                                    (* Use the BIOS COM port init routine *)
  792.  
  793.    BIOS_RS232_Init( ComPort - 1 , ComParm );
  794.  
  795.                                    (* If > 9600 baud, we have to screw *)
  796.                                    (* around a bit                     *)
  797.  
  798.    IF ( BaudRate = 19200 ) THEN
  799.       BEGIN
  800.  
  801.          I := PORT[ UART_LCR + Async_Base ];
  802.          PORT[ UART_LCR + Async_Base ] := I OR $80;
  803.  
  804.          PORT[ UART_THR + Async_Base ] := 6;
  805.          PORT[ UART_IER + Async_Base ] := 0;
  806.  
  807.          I := PORT[ UART_LCR + Async_Base ];
  808.          PORT[ UART_LCR + Async_Base ] := I AND $7F;
  809.  
  810.       END;
  811.                                    (* Now fix up mark, space parity *)
  812.  
  813.    IF ( ( Parity = 'M' ) OR ( Parity = 'S' ) ) THEN
  814.       BEGIN
  815.  
  816.          I := PORT[ UART_LCR + Async_Base ];
  817.          PORT[ UART_LCR + Async_Base ] := $80;
  818.  
  819.          ComParm := WordSize OR ( ( StopBits - 1 ) SHL 2 );
  820.  
  821.          CASE Parity OF
  822.             'M' : ComParm := ComParm OR $0028;
  823.             'S' : ComParm := ComParm OR $0038;
  824.             ELSE ;
  825.          END (* CASE *);
  826.  
  827.          PORT[ UART_LCR + Async_Base ] := ComParm;
  828.  
  829.       END;
  830.                                    (* Clear any pending errors on *)
  831.                                    (* async line                  *)
  832.    Async_Clear_Errors;
  833.  
  834. END   (* Async_Reset_Port *);
  835.  
  836. (*----------------------------------------------------------------------*)
  837. (*               Async_Open --- Open communications port                *)
  838. (*----------------------------------------------------------------------*)
  839.  
  840. FUNCTION Async_Open( ComPort       : INTEGER;
  841.                      BaudRate      : INTEGER;
  842.                      Parity        : CHAR;
  843.                      WordSize      : INTEGER;
  844.                      StopBits      : INTEGER  ) : BOOLEAN;
  845.  
  846. (*----------------------------------------------------------------------*)
  847. (*                                                                      *)
  848. (*     Function:   Async_Open                                           *)
  849. (*                                                                      *)
  850. (*     Purpose:    Opens communications port                            *)
  851. (*                                                                      *)
  852. (*     Calling Sequence:                                                *)
  853. (*                                                                      *)
  854. (*        Flag := Async_Open( ComPort       : INTEGER;                  *)
  855. (*                            BaudRate      : INTEGER;                  *)
  856. (*                            Parity        : CHAR;                     *)
  857. (*                            WordSize      : INTEGER;                  *)
  858. (*                            StopBits      : INTEGER) : BOOLEAN;       *)
  859. (*                                                                      *)
  860. (*           ComPort  --- which port (1 though 3)                       *)
  861. (*           BaudRate --- Baud rate (110 to 19200)                      *)
  862. (*           Parity   --- "E" for even, "O" for odd, "N" for none,      *)
  863. (*                        "S" for space, "M" for mark.                  *)
  864. (*           WordSize --- Bits per character  (5 through 8)             *)
  865. (*           StopBits --- How many stop bits  (1 or 2)                  *)
  866. (*                                                                      *)
  867. (*           Flag returned TRUE if port initialized successfully;       *)
  868. (*           Flag returned FALSE if any errors.                         *)
  869. (*                                                                      *)
  870. (*     Calls:                                                           *)
  871. (*                                                                      *)
  872. (*        Async_Reset_Port --- initialize RS232 port                    *)
  873. (*        DOS_Set_Intrpt   --- set address of RS232 interrupt routine   *)
  874. (*                                                                      *)
  875. (*----------------------------------------------------------------------*)
  876.  
  877. BEGIN  (* Async_Open *)
  878.                              (* If port open, close it down first.  *)
  879.    IF Async_Open_Flag THEN
  880.       Async_Close( FALSE );
  881.                              (* Choose communications port *)
  882.  
  883.    IF ( ComPort < 1 ) THEN
  884.       ComPort := 1
  885.    ELSE IF ( ComPort > MaxComPorts ) THEN
  886.       ComPort := MaxComPorts;
  887.  
  888.    Async_Port  := ComPort;
  889.    Async_Base  := Com_Base [ ComPort ];
  890.    Async_Irq   := Com_Irq  [ ComPort ];
  891.    Async_RS232 := Com_RS232[ ComPort ];
  892.  
  893.                                    (* Set register pointers for ISR routine *)
  894.  
  895.    Async_Uart_IER  := Async_Base + UART_IER;
  896.    Async_Uart_IIR  := Async_Base + UART_IIR;
  897.    Async_Uart_MSR  := Async_Base + UART_MSR;
  898.    Async_Uart_LSR  := Async_Base + UART_LSR;
  899.  
  900.                                    (* Check if given port installed *)
  901.  
  902.    IF (Port[UART_IIR + Async_Base] and $00F8) <> 0 THEN
  903.       Async_Open := FALSE          (* Serial port not installed *)
  904.    ELSE
  905.       BEGIN   (* Open the port *)
  906.  
  907.                                    (* Get current interrupt address *)
  908.  
  909.          DOS_Get_Intrpt( Async_Irq + 8 , Async_Save_Iaddr[1],
  910.                                          Async_Save_Iaddr[2]  );
  911.  
  912.                                    (* Set interrupt routine address *)
  913.  
  914.          DOS_Set_Intrpt( Async_Irq + 8 , CSeg , Ofs( Async_Isr ) );
  915.  
  916.                                    (* Set up UART                   *)
  917.  
  918.          Async_Reset_Port( ComPort, BaudRate, Parity, WordSize, StopBits );
  919.  
  920.          Async_Open      := TRUE;
  921.          Async_Open_Flag := TRUE;
  922.  
  923.                                    (* Reset XON/XOFF flags          *)
  924.  
  925.          Async_XOFF_Sent        := FALSE;
  926.          Async_XOFF_Received    := FALSE;
  927.          Async_XOFF_Rec_Display := FALSE;
  928.          Async_XON_Rec_Display  := FALSE;
  929.          Async_Send_XOFF        := FALSE;
  930.  
  931.     END;
  932.  
  933. END   (* Async_Open *);
  934.  
  935.